package org.springboot.aop.config;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AopControllerAspect {

	/**
	 * 切入点定义
	 * - 方法用 execution 指定
	 *  @Pointcut("execution(* org.springboot.aop.controller.AopController.*(..))")
	 * - 注解用 @annotation 指定，注解的类型是 @interface，算是一种特殊的接口
	 *  @Pointcut("@annotation(org.springboot.aop.annotation.UploadObs)")
	 * - 支持逻辑运算符
	 *  @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping) 
	 *   || @annotation(org.springframework.web.bind.annotation.GetMapping)
	 *   || @annotation(org.springframework.web.bind.annotation.PostMapping)")
	 * 格式：返回值类型  全限定类名|接口名.方法名(参数表）
	 *  - 如果使用接口，会代理该接口所有的实现类
	 *  - 可使用通配符 *，参数表可使用具体类型，比如(int, String)，也可用(…)表示任意参数类型、参数个数
	 */
	
    @Pointcut("execution(* org.springboot.aop.controller.AopController.*(..))")
    private void pointCut() {
    	
    }

    /**
     * value 属性指定切入点，可以直接引用其它切入点，也可以现配
     */
    @Before("pointCut()")
    public void before() {
        System.out.println("正在执行前置通知 before...");
    }

    @After("pointCut()")
    public void after() {
        System.out.println("正在执行后置通知 after...");
    }

    @AfterReturning(value = "pointCut()", returning = "obj")
    public void afterReturning(Object obj) {
        System.out.println("正在执行返回通知 afterReturning...");
        System.out.println("目标方法的返回值是：" + obj);
    }

    @AfterThrowing(value = "pointCut()", throwing = "e")
    public void afterThrowing(JoinPoint point, Exception e) {
        System.out.println("正在执行异常通知 afterThrowing...");
        System.out.println("异常信息：" + e.getMessage());
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        // 前增强
        System.out.println("正在执行前增强...");
        // 调用目标方法
        Object object = proceedingJoinPoint.proceed();
        // 后增强
        System.out.println("正在执行后增强...");
        // 返回目标方法的返回值
        return object;
    }

}
